package org.erp.product.strategy.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import lombok.AllArgsConstructor;
import org.erp.common.constant.ProductConstant;
import org.erp.common.enums.DeviceInventoryEvent;
import org.erp.common.manager.StockBatchLockManager;
import org.erp.product.domain.dto.CallbackDto;
import org.erp.product.domain.dto.ConnectLogAddDto;
import org.erp.product.domain.dto.TransferLogAddDto;
import org.erp.product.domain.entity.ConnectLog;
import org.erp.product.domain.entity.ProductInfo;
import org.erp.product.domain.entity.RepairInfo;
import org.erp.product.infrastructure.annotation.DeviceEvent;
import org.erp.product.infrastructure.convert.ConnectConvert;
import org.erp.product.infrastructure.convert.ProductInfoConvert;
import org.erp.product.infrastructure.convert.RepairInfoConvert;
import org.erp.product.infrastructure.enums.*;
import org.erp.product.service.ConnectLogService;
import org.erp.product.service.ProductInfoService;
import org.erp.product.service.RepairInfoService;
import org.erp.product.service.TransferLogService;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Set;
import java.util.stream.Collectors;

@Component
@AllArgsConstructor
public class DeviceEventHandler {

    private final ConnectLogService connectLogService;

    private final ConnectConvert connectConvert;

    private final StockBatchLockManager stockBatchLockManager;

    private final ProductInfoService productInfoService;

    private final RepairInfoService repairInfoService;

    private final TransferLogService transferLogService;

    private final ProductInfoConvert productInfoConvert;

    private final RepairInfoConvert repairInfoConvert;

    /**
     * 发起调拨 (ALLOCATE)
     */
    @Transactional(rollbackFor = Exception.class)
    @DeviceEvent(DeviceInventoryEvent.ALLOCATE)
    public void allocate(CallbackDto dto) {
        List<ConnectLog> list = dto.getConnectLogAddDtoList().stream()
                .map(c -> connectConvert.dtoConvert(c, dto)).toList();
        connectLogService.saveBatch(list);
        stockBatchLockManager.releaseAll(dto.getBatchId(), ProductConstant.PRODUCT_BUSY_STOCKS);
    }

    /**
     * 接驳完成 (HANDOVER)
     */
    @Transactional(rollbackFor = Exception.class)
    @DeviceEvent(DeviceInventoryEvent.HANDOVER)
    public void handover(CallbackDto dto) {
        List<Long> stockIds = dto.getConnectLogAddDtoList().stream().map(ConnectLogAddDto::getStockId).toList();
        List<ConnectLog> connectLogList = connectLogService.list(new QueryWrapper<ConnectLog>().lambda()
                .in(ConnectLog::getStockId, stockIds));
        connectLogService.updateStatus(connectLogList, ConnectEventEnum.CONNECTION);
        List<ConnectLog> repairConnectList = new ArrayList<>();
        List<ConnectLog> inspectionConnectList = new ArrayList<>();
        connectLogList.forEach(c -> {
            if (TransferTypeEnum.REPAIR_TRANSFER.getCode().equals(c.getTransferType())) {
                repairConnectList.add(c);
            } else {
                inspectionConnectList.add(c);
            }
        });
        List<RepairInfo> repairList = List.of();
        List<ProductInfo> productList;
        if (!repairConnectList.isEmpty()) {
            repairList = repairConnectList.stream().map(repairInfoConvert::convert).toList();
            repairInfoService.saveBatch(repairList);
        }
        List<ProductInfo> existProductList;
        List<ProductInfo> unexistProductList = List.of();
        if (!inspectionConnectList.isEmpty()) {
            productList = inspectionConnectList.stream().map(productInfoConvert::convert).toList();
            Set<Long> productStockIds = productList.stream().map(ProductInfo::getStockId).collect(Collectors.toSet());
            existProductList = productInfoService.list(new QueryWrapper<ProductInfo>().lambda()
                    .in(ProductInfo::getStockId, productStockIds));
            List<Long> existStockIds = existProductList.stream().map(ProductInfo::getStockId).toList();
            unexistProductList = productList.stream()
                    .filter(p -> existStockIds.contains(p.getStockId())).toList();
            if (!existProductList.isEmpty()) {
                productList.forEach(p -> {
                    existProductList.forEach(e -> {
                        if (e.getStockId().equals(p.getStockId())) {
                            e.setTransferType(p.getTransferType());
                            if (TransferTypeEnum.SELL_TRANSFER.getCode().equals(p.getTransferType())) {
                                e.setInspectionStatus(InspectionStatusEnum.QUALIFIED.getCode());
                            } else {
                                e.setInspectionStatus(p.getInspectionStatus());
                            }
                            if (TransferTypeEnum.DICKER_TRANSFER.getCode().equals(p.getTransferType())) {
                                e.setDickerPrice(p.getDickerPrice());
                            }
                        }
                    });
                });
                productInfoService.updateBatchStatus(existProductList, InspectionEventEnum.INSPECTION_DICKER_CONNECT);
            }
            productInfoService.saveBatch(unexistProductList);
        } else {
            existProductList = List.of();
        }
        TransferLogAddDto transferLogAddDto = new TransferLogAddDto();
        existProductList.addAll(unexistProductList);
        transferLogAddDto.setProductInfoList(existProductList);
        transferLogAddDto.setRepairInfoList(repairList);
        transferLogAddDto.setConnectOldStatus(connectLogList.get(0).getOldStatus());
        transferLogAddDto.setConnectNewStatus(connectLogList.get(0).getNewStatus());
        transferLogAddDto.setOperationId(connectLogList.get(0).getOperationId());
        transferLogAddDto.setOperationName(connectLogList.get(0).getOperationName());
        transferLogAddDto.setOldStatus(-1);
        transferLogService.saveBatch(transferLogAddDto, EventCodeEnum.CONNECT, ConnectEventEnum.CONNECTION);
        stockBatchLockManager.releaseAll(dto.getBatchId(), ProductConstant.PRODUCT_BUSY_CONNECT_LOGS);
    }

    /**
     * 调拨驳回 (REJECT)
     */
    @DeviceEvent(DeviceInventoryEvent.REJECT)
    public void reject(CallbackDto dto) {
        List<Long> stockIds = dto.getConnectLogAddDtoList().stream().map(ConnectLogAddDto::getStockId).toList();
        List<ConnectLog> connectLogList = connectLogService.list(new QueryWrapper<ConnectLog>().lambda()
                .in(ConnectLog::getStockId, stockIds));
        connectLogService.updateStatus(connectLogList, ConnectEventEnum.OVERRULE);
    }

    /**
     * 驳回到入库 (REJECT_TO_INBOUND)
     */
    @DeviceEvent(DeviceInventoryEvent.REJECT_TO_INBOUND)
    public void rejectToInbound(CallbackDto dto) {
        // ...
    }

    /**
     * 申请返库 (REQUEST_RETURN)
     */
    @DeviceEvent(DeviceInventoryEvent.REQUEST_RETURN)
    public void requestReturn(CallbackDto dto) {
        // ...
    }

    /**
     * 撤销驳回 (CANCEL_REJECT)
     */
    @DeviceEvent(DeviceInventoryEvent.CANCEL_REJECT)
    public void cancelReject(CallbackDto dto) {
        // ...
    }
}
